﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SMS_Server;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SMS_Server_Manager
{
    public partial class Mainform : Form
    {
        public Mainform()
        {
            InitializeComponent();
        }

        private void Mainform_Load(object sender, EventArgs e)
        {
            AllowedCodes.Text = Global.AllowedCountryCodes;
            FunctionList.Items.Clear();
            foreach (Function f in Global.Functions)
            {
                FunctionList.Items.Add(f);
            }
            Thread th = new Thread(MonitorServer);
            th.Start();
        }

        #region Importing Number
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Text file|*.txt";
            ofd.CheckPathExists = true;
            ofd.Multiselect = false;
            System.Windows.Forms.DialogResult DR = ofd.ShowDialog();
            if (DR != System.Windows.Forms.DialogResult.OK)
                return;
            string[] data = System.IO.File.ReadAllLines(ofd.FileName);

            int count = 0;
            string numbers = "";
            foreach (string s in data)
            {
                if (string.IsNullOrEmpty(s)) continue;
                if (s[0] != '+') continue;
                string valid = "0123456789";
                for (int i = 1; i < s.Length;i++ )
                {
                    if (valid.IndexOf(s[i]) < 0) continue;
                }
                if (numbers != "") numbers += ";";
                numbers += s;
                count++;
            }
            MessageBox.Show(count + " numbers has been imported", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
            Phonenumbers.Text = numbers;
        }
        private void button1_MouseHover(object sender, EventArgs e)
        {
            label6.Visible = true;
        }
        private void button1_MouseLeave(object sender, EventArgs e)
        {
            label6.Visible = false;
        }
        #endregion

        #region Add/Remove Functions and Actions

        private void AddFunction_Click(object sender, EventArgs e)
        {
            AddFunction af = new AddFunction();
            af.ViewDialog(this);
        }

        private void RemoveFunction_Click(object sender, EventArgs e)
        {
            if (FunctionList.SelectedItem == null) return;
            System.Windows.Forms.DialogResult DR = MessageBox.Show("Do you really want to remove " + FunctionList.Items[FunctionList.SelectedIndex].ToString() + "?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (DR == System.Windows.Forms.DialogResult.No) return;
            Function function=(Function)FunctionList.Items[FunctionList.SelectedIndex];
            DataAccess DA = new DataAccess(Global.GetConfigurationDatabaseName(), Global.DatabasePassword);
            DA.CommandString = "DELETE FROM Functions WHERE FunctionName=@FunctionName;";
            DA.AddParameter("@FunctionName", function.FunctionName);
            DA.ExecuteNonQuery();
            DA.Close();
            DetailsLabel.Text = "";
            FunctionList.Items.RemoveAt(FunctionList.SelectedIndex);
            Global.Functions.Remove(function);
            Global.unsaved_changes = true;
        }

        private void RemoveAction_Click(object sender, EventArgs e)
        {
            if (ActionList.SelectedItem == null) return;
            System.Windows.Forms.DialogResult DR = MessageBox.Show("Do you really want to remove " + ActionList.Items[ActionList.SelectedIndex].ToString() + " from " + FunctionList.Items[FunctionList.SelectedIndex].ToString() + "?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (DR == System.Windows.Forms.DialogResult.No) return;
            Incoming_Action IA = (Incoming_Action)ActionList.Items[ActionList.SelectedIndex];
            DataAccess DA = new DataAccess(Global.GetConfigurationDatabaseName(), Global.DatabasePassword);
            switch (IA.ActionType())
            {
                case ActionTypes.StaticResponse:
                    DA.CommandString = "DELETE FROM Action_Static WHERE ActionID=@ActionID;";
                    break;
                case ActionTypes.SMS_Email:
                    DA.CommandString = "DELETE FROM Action_SMS_Email WHERE ActionID=@ActionID;";
                    break;
                case ActionTypes.Search:
                    DA.CommandString = "DELETE FROM Action_Search WHERE ActionID=@ActionID;";
                    break;
                case ActionTypes.Insert:
                    DA.CommandString = "DELETE FROM Action_Insert WHERE ActionID=@ActionID;";
                    break;
                case ActionTypes.Forword2TCP:
                    DA.CommandString = "DELETE FROM Action_ToTCP WHERE ActionID=@ActionID;";
                    break;
                case ActionTypes.Forward2HTTP:
                    DA.CommandString = "DELETE FROM Action_ToHTTP WHERE ActionID=@ActionID;";
                    break;
            }
            DA.AddParameter("@ActionID", IA.ActionID());
            DA.ExecuteNonQuery();
            DA.Close();
            ActionList.Items.RemoveAt(ActionList.SelectedIndex);
            Function function = (Function)FunctionList.Items[FunctionList.SelectedIndex];
            DetailsLabel.Text = function.FunctionName + " " + function.ParamFormat;
            function.Actions.Remove(IA);
            Global.unsaved_changes = true;
        }

        private void FunctionList_SelectedIndexChanged(object sender, EventArgs e)
        {
            ActionList.Items.Clear();
            RemoveAction.Enabled = false;
            RemoveAction.Image = Properties.Resources.remove_button_disabled;
            AddAction.Enabled = false;
            AddAction.Image = Properties.Resources.add_button_disabled;
            ActionProperties.Enabled = false;
            ActionProperties.Image = Properties.Resources.properties_button_disabled;
            if (FunctionList.SelectedItem == null)
            {
                RemoveFunction.Enabled = false;
                RemoveFunction.Image = Properties.Resources.remove_button_disabled;
                DetailsLabel.Text = "";
                return;
            }
            AddAction.Enabled = true;
            AddAction.Image = Properties.Resources.add_button_enabled;
            RemoveFunction.Enabled = true;
            RemoveFunction.Image = Properties.Resources.remove_button_enabled;

            Function function = (Function)FunctionList.Items[FunctionList.SelectedIndex];
            foreach (Incoming_Action IA in function.Actions)
            {
                ActionList.Items.Add(IA);
            }
            DetailsLabel.Text = function.FunctionName + " " + function.ParamFormat;
            if (((Function)FunctionList.Items[FunctionList.SelectedIndex]).FunctionName == "Unknown")
            {
                RemoveFunction.Enabled = false;
                RemoveFunction.Image = Properties.Resources.remove_button_disabled;
            }
        }

        private void ActionList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (ActionList.SelectedItem == null)
            {
                RemoveAction.Enabled = false;
                RemoveAction.Image = Properties.Resources.remove_button_disabled;
                ActionProperties.Enabled = false;
                ActionProperties.Image = Properties.Resources.properties_button_disabled;
                DetailsLabel.Text = "";
                return;
            }
            RemoveAction.Enabled = true;
            RemoveAction.Image = Properties.Resources.remove_button_enabled;
            ActionProperties.Enabled = true;
            ActionProperties.Image = Properties.Resources.properties_button_enabled;

            Function function = (Function)FunctionList.Items[FunctionList.SelectedIndex];
            string details = function.FunctionName + " " + function.ParamFormat;
            details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
            Incoming_Action IA = (Incoming_Action)ActionList.Items[ActionList.SelectedIndex];

            switch (IA.ActionType())
            {
                case ActionTypes.StaticResponse:
                    details += "Response Text:" + Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += ((Action_StaticResponse)IA).ResponseString;
                    break;
                case ActionTypes.SMS_Email:
                    Action_SMS_Email ase = (Action_SMS_Email)IA;
                    details += "Will be  forworded by " + ase.Mode.ToString() + " to: ";
                    details += ase.Address;
                    break;
                case ActionTypes.Search:
                    Action_Search a_s = (Action_Search)IA;
                    details += "Connection String: ";
                    details += a_s.ConnectionString;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Connector: " + a_s.Connector.ToString();
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Table Name: " + a_s.TableName;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Search Columns: " + a_s.SearchColumns;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Response Columns: " + a_s.ResponseColumns;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Response Format: " + a_s.ResponseFormat;
                    break;
                case ActionTypes.Insert:
                    Action_Insert a_i = (Action_Insert)IA;
                    details += "Connection String: ";
                    details += a_i.ConnectionString;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Connector: " + a_i.Connector.ToString();
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Table Name: " + a_i.TableName;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Columns: " + a_i.Columns;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Response Columns: " + a_i.ResponseColumns;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Response Format: " + a_i.ResponseFormat;
                    break;
                case ActionTypes.Forword2TCP:
                    Action_Forward2TCP aftcp = (Action_Forward2TCP)IA;
                    details += "IP: ";
                    details += aftcp.IP;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Port: " + aftcp.Port;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Has Response:" + aftcp.HasResponse.ToString();
                    break;
                case ActionTypes.Forward2HTTP:
                    Action_Forward2HTTP afhttp = (Action_Forward2HTTP)IA;
                    details += "URL: ";
                    details += afhttp.URL;
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Method: " + afhttp.Method.ToString();
                    details += Encoding.UTF8.GetString(new byte[] { 13, 10 });
                    details += "Has Response:" + afhttp.HasResponse.ToString();
                    break;
            }

            DetailsLabel.Text = details;
        }

        private void AddAction_Click(object sender, EventArgs e)
        {
            Forms.ActionChooser AC = new Forms.ActionChooser();
            AC.ViewDialog(this);
        }

        private void ActionProperties_Click(object sender, EventArgs e)
        {
            Incoming_Action IA = (Incoming_Action)ActionList.SelectedItem;
            switch (IA.ActionType())
            {
                case ActionTypes.StaticResponse:
                    Forms.StaticResponse sr = new Forms.StaticResponse();
                    sr.Static_Response = (Action_StaticResponse)ActionList.SelectedItem;
                    sr.ViewDialog(this);
                    break;
                case ActionTypes.SMS_Email:
                    Forms.SmsEmail se = new Forms.SmsEmail();
                    se.SMS_Email = (Action_SMS_Email)ActionList.SelectedItem;
                    se.ViewDialog(this);
                    break;
                case ActionTypes.Search:
                    Forms.SearchFrom sf = new Forms.SearchFrom();
                    sf.Search = (Action_Search)ActionList.SelectedItem;
                    sf.ViewDialog(this);
                    break;
                case ActionTypes.Insert:
                    Forms.InsertInto ii = new Forms.InsertInto();
                    ii.Insert = (Action_Insert)ActionList.SelectedItem;
                    ii.ViewDialog(this);
                    break;
                case ActionTypes.Forword2TCP:
                    Forms.ToTCP tt = new Forms.ToTCP();
                    tt.To_TCP = (Action_Forward2TCP)ActionList.SelectedItem;
                    tt.ViewDialog(this);
                    break;
                case ActionTypes.Forward2HTTP:
                    Forms.ToHTTP th = new Forms.ToHTTP();
                    th.To_HTTP = (Action_Forward2HTTP)ActionList.SelectedItem;
                    th.ViewDialog(this);
                    break;
            }
        }

        #endregion

        #region ToolStripController

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutUs AU = new AboutUs();
            AU.ShowDialog(this);
        }

        private void StartServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StartServerToolStripMenuItem.Enabled = false;
            SMSServiceController.Start();
            SMSServiceController.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running);
        }

        private void StopServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StopServerToolStripMenuItem.Enabled = false;
            if (SMSServiceController.Status == System.ServiceProcess.ServiceControllerStatus.Running)
            {
                SMSServiceController.ExecuteCommand(128);
                SMSServiceController.Stop();
            }
            SMSServiceController.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped);
        }

        private void applyChangesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Forms.ApplyDialogue ad = new Forms.ApplyDialogue();
            ad.ShowDialog();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (Global.unsaved_changes)
            {
                System.Windows.Forms.DialogResult dr = MessageBox.Show("There is unsaved changes in the configuration file. Unsaved changes will be lost if you exit. Would you like to apply changes now? Click YES to apply, NO to exit", "Notice", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (dr == System.Windows.Forms.DialogResult.Yes)
                {
                    Forms.ApplyDialogue ad = new Forms.ApplyDialogue();
                    System.Windows.Forms.DialogResult dr2 = ad.ShowDialog();
                    if (dr2 == System.Windows.Forms.DialogResult.Cancel) return;
                }
                else if (dr == System.Windows.Forms.DialogResult.No)
                {
                    Application.Exit();
                }
                else if (dr == System.Windows.Forms.DialogResult.Cancel)
                {
                    return;
                }
            }
            else
                Application.Exit();
        }

        #endregion

        #region Server Status Monitor
       
        private delegate void StringParam(string str);

        private bool formclosed = false;

        private void MonitorServer()
        {
            StringParam rs = new StringParam(RefreshStatus);

            while (!formclosed)
            {
                try
                {
                    this.Invoke(rs, new object[] { "" });
                }
                catch {}
                Thread.Sleep(5000);
            }
        }

        TcpClient Monitoringtcp=new TcpClient();
        NetworkStream Monitorns;
        StreamReader Monitorsr;
        StreamWriter Monitorsw;

        private void RefreshStatus(string command)
        {
            //Update service status
            if (SMSServiceController.Status == System.ServiceProcess.ServiceControllerStatus.Running)
            {
                ServerStatus.Image = Properties.Resources.green_led;
                ChangeModemButton.Enabled = true;
                StartServerToolStripMenuItem.Enabled = false;
                StopServerToolStripMenuItem.Enabled = true;
                //Check server activity
                try
                {
                    if (!Monitoringtcp.Connected)
                    {
                        Monitoringtcp = new TcpClient();
                        Monitoringtcp.Connect(Global.GetDefaultIP(), 2000);
                        Monitorns = Monitoringtcp.GetStream();
                        Monitorsr = new StreamReader(Monitorns);
                        Monitorsw = new StreamWriter(Monitorns);
                    }
                    //Lets get the signal quality
                    Monitorsw.WriteLine("SQ");
                    Monitorsw.Flush();
                    sqDisplay1.SignalQuality = int.Parse(Monitorsr.ReadLine());
                    //Lets get the processing que
                    Monitorsw.WriteLine("NPQ");
                    Monitorsw.Flush();
                    IncomingQue.Text = Monitorsr.ReadLine();
                    //Lets get the sending que
                    Monitorsw.WriteLine("NSQ");
                    Monitorsw.Flush();
                    OutgoingQue.Text = Monitorsr.ReadLine();
                    //lets get the device details.
                    Monitorsw.WriteLine("CD");
                    Monitorsw.Flush();
                    string devicedetails = Monitorsr.ReadLine();
                    ModemName.Text = devicedetails.Split(',')[0];
                    if (newModemName.Text == "New: " + ModemName.Text) newModemName.Text = "";
                    statl.Text = "Ready";
                    if (ModemName.Text == "") SendButton.Enabled = false; else SendButton.Enabled = true;
                }
                catch
                {
                    statl.Text = "Server is unreachable...";
                    SendButton.Enabled = false;
                    ChangeModemButton.Enabled = false;
                    sqDisplay1.SignalQuality = 0;
                    IncomingQue.Text = "0";
                    OutgoingQue.Text = "0";
                    ModemName.Text = "";
                }

            }
            else
            {
                ServerStatus.Image = Properties.Resources.disabled_led;
                SendButton.Enabled = false;
                ChangeModemButton.Enabled = false;
                sqDisplay1.SignalQuality = 0;
                IncomingQue.Text = "0";
                OutgoingQue.Text = "0";
                ModemName.Text = "";
                StartServerToolStripMenuItem.Enabled = true;
                StopServerToolStripMenuItem.Enabled = false;
            }
            if (Global.unsaved_changes)
            {
                applyChangesToolStripMenuItem.Enabled = true;
            }
            else
            {
                applyChangesToolStripMenuItem.Enabled = false;
            }
        }
        
        #endregion

        private void SendButton_Click(object sender, EventArgs e)
        {
            string message = Messagebox.Text.Replace(Encoding.ASCII.GetString(new byte[] { 13 }), "`");
            if (string.IsNullOrEmpty(message))
            {
                MessageBox.Show("An empty message can not be sent", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            string phonenumbers = Phonenumbers.Text;
            phonenumbers = phonenumbers.Replace(" ", "");
            string[] numbers = phonenumbers.Split(';');
            string refurbished = "";
            foreach (string number in numbers)
            {
                if (!validators.IsValidPhoneNumber(number))
                {
                    if (string.IsNullOrEmpty(number)) continue;
                    MessageBox.Show(number + " is not a valid phone number", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                if (refurbished != "") refurbished += ";";
                refurbished += number;
            }
            string PhoneNumbers = refurbished;
            if (string.IsNullOrEmpty(PhoneNumbers))
            {
                MessageBox.Show("Phone numbers are required", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            Phonenumbers.Text = PhoneNumbers;

            try
            {
                TcpClient tcp = new TcpClient();
                tcp.Connect(Global.GetDefaultIP(), 2000);
                NetworkStream ns = tcp.GetStream();
                StreamReader sr = new StreamReader(ns);
                StreamWriter sw = new StreamWriter(ns);
                //lets get the device details.
                sw.WriteLine("SMS");//request to accept SMS
                sw.Flush();
                sw.WriteLine(PhoneNumbers);
                sw.Flush();
                sw.WriteLine(message);
                sw.Flush();

                string response = sr.ReadLine();

                if (response != "SUCCESS")
                {
                    MessageBox.Show(response, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    Phonenumbers.Text = "";
                    Messagebox.Text = "";
                    MessageBox.Show("Message has been accepted and in que", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }

                tcp.Close();
            }
            catch
            {
                MessageBox.Show("SMS server is unreachable", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void ChangeModemButton_Click(object sender, EventArgs e)
        {
            Forms.ChangeModem cm = new Forms.ChangeModem();
            cm.ViewDialog(this);
        }

        private void SaveButton_Click(object sender, EventArgs e)
        {
            string countrycodes = AllowedCodes.Text;
            countrycodes = countrycodes.Replace(" ", "");
            string[] codes = countrycodes.Split(';');
            string refurbished = "";
            foreach (string code in codes)
            {
                if (!IsValidCountryCode(code))
                {
                    if (string.IsNullOrEmpty(code)) continue;
                    MessageBox.Show(code + " is not a valid country code", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                if (refurbished != "") refurbished += ";";
                refurbished += code;
            }
            AllowedCodes.Text = refurbished;
            Global.AllowedCountryCodes = refurbished;
            //lets save to database
            DataAccess DA = new DataAccess(Global.GetConfigurationDatabaseName(), Global.DatabasePassword);
            //update isvalidserial
            DA.CommandString = "Update General_Config SET ParamValue=@ParamValue WHERE ParamName=@ParamName;";
            DA.AddParameter("@ParamValue", Global.AllowedCountryCodes);
            DA.AddParameter("@ParamName", "AllowedCountryCodes");
            DA.ExecuteNonQuery();
            DA.Close();
            Global.unsaved_changes = true;
        }

        private bool IsValidCountryCode(string countryCode)
        {
            if (string.IsNullOrEmpty(countryCode)) return false;
            if (countryCode[0] != '+') return false;
            if (countryCode.Length < 2) return false;
            //Valid character set, actually its a process of white list validation
            string ValidChars = "1234567890";
            countryCode = countryCode.Substring(1);
            //check if there is any invalid character in the string
            foreach (char c in countryCode)
            {
                if (ValidChars.IndexOf(c) < 0) return false;
            }
            return true;
        }

        private void Mainform_FormClosing(object sender, FormClosingEventArgs e)
        {

            if (Global.unsaved_changes)
            {
                System.Windows.Forms.DialogResult dr = MessageBox.Show("There is unsaved changes in the configuration file. Unsaved changes will be lost if you exit. Would you like to apply changes now? Click YES to apply, NO to exit", "Notice", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (dr == System.Windows.Forms.DialogResult.Yes)
                {
                    Forms.ApplyDialogue ad = new Forms.ApplyDialogue();
                    System.Windows.Forms.DialogResult dr2 = ad.ShowDialog();
                    if (dr2 == System.Windows.Forms.DialogResult.Cancel)
                    {
                        e.Cancel = true;
                        return;
                    }
                }
                else if (dr == System.Windows.Forms.DialogResult.No)
                {
                    formclosed = true;
                    Application.Exit();
                }
                else if (dr == System.Windows.Forms.DialogResult.Cancel)
                {
                    e.Cancel = true;
                    return;
                }
            }
            else
            {
                formclosed = true;
                Application.Exit();
            }
        }

        private void DonationButton_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=C2EW8NAF2VWS4&lc=GB&item_name=Onuprova&item_number=Opensource%20SMS%20server&currency_code=GBP&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted");
        }

    }
}
